Skip to content

Webgpu render for Manim - #4968

Open
mayanksuman wants to merge 35 commits into
ManimCommunity:mainfrom
mayanksuman:webgpu_render
Open

Webgpu render for Manim#4968
mayanksuman wants to merge 35 commits into
ManimCommunity:mainfrom
mayanksuman:webgpu_render

Conversation

@mayanksuman

Copy link
Copy Markdown

Overview: What does this pull request change?

This adds a new WebGPURenderer (manim/renderer/webgpu/), selectable via --renderer webgpu, built on top of wgpu-py. It is a from-scratch renderer implementation that reaches rough feature parity with the existing OpenGL renderer:

  • Core renderer, camera, and an interactive preview window (webgpu_renderer.py, webgpu_renderer_window.py, webgpu_interactive.py), including live file-watching / rerun() support and configurable MSAA.
  • VMobject fill/stroke rendering (webgpu_vmobject_rendering.py) using a Slug-algorithm-based fill shader and analytic SDF anti-aliasing for strokes, with combined fill+stroke rendering for planar objects and gradient support.
  • 3D support: perspective projection, surfaces/meshes (combined surface+mesh shader), textures, images (including ImageMobjectFromCamera and ZoomedScene), and TrueDot.
  • A new lighting system (manim/mobject/three_d/light_source.py, exported from manim), with per-surface diffuse/specular strength and reflection parameters, and multiple light source types.
  • Complex SVG support and static-frame optimization.
  • A base_renderer.py structural interface (typing.Protocol) shared by all renderers (Cairo, OpenGL, WebGPU) to keep the renderer contract explicit.
  • wgpu-py added as a dependency; new RendererType.WEBGPU enum value and CLI wiring in manim/cli/render/commands.py.

Motivation and Explanation: Why and how do your changes improve the library?

Manim currently ships two renderers, Cairo (CPU) and OpenGL, neither of which map well onto modern, cross-platform GPU APIs or the web/WASM target. WebGPU is the emerging cross-platform graphics/compute standard (native via wgpu-py, and eventually browsers), and adding a WebGPU backend lays the groundwork for faster rendering and future in-browser Manim playback, while reusing Manim's existing scene/mobject model through the new shared renderer interface.

The implementation intentionally avoids geometry shaders (unsupported in WebGPU) by using compute-shader/SDF-based techniques for stroke expansion and anti-aliasing instead of the geometry-shader-heavy path used by the classic OpenGL pipeline.

Further Information and Comments

This is an early-stage, experimental renderer (Phase 1–5 per the internal implementation plan: minimum viable VMobject rendering → full VMobject support → 3D/surfaces/textures → video output/preview window → feature parity with the OpenGL renderer). Feedback on API shape (especially base_renderer.py's shared interface) and on scope for an initial merge vs. further splitting into smaller PRs is very welcome.

Now, if OpenGL renderer is not used then OpenGL classes are also not loaded.
For OpenGL rednerer, there is no change in logic. Just wanted to ensure clear
separation from OpenGL code for other renderers.
Using ``typing.Protocol`` (rather than an ABC) means the existing
``CairoRenderer`` and ``OpenGLRenderer`` satisfy the interface automatically
without any inheritance changes.
All Protocol methods of WebGPURender (as defined in manim/renderer/base_renderer.py)
is defined. Camera (both 2D and 3D prospective) and
Loop-Blinn fill anti-aliasing for Cubic Bezeir Curves are implemented. Phong
Shader is implemented for rendering surfaces.
Concatenate all fill vertices into one buffer, all stroke vertices into another.
Results in lower number of call to shader and faster execution.
The reference Slug implementation is available at https://github.com/EricLengyel/Slug
authored by Eric Lengyel. A fill shader based on Slug algorithm is implemented
in this commit.
Added initial differentiation between camera and lighting. Right now Camera
only uses orthographic projection.
The behavior now matches with Cairo's.
Having separate fill and stroke shaders was complicating design regarding
drawing order. Combining them for planar object has reduced the CPU computation
also.
Cairo and OpenGL composite a static background image with only the
moving_mobjects each frame. For scenes with many static elements
this is a major perf win — only the animated subset is re-drawn.
Now, four different kind of light source exist: ambient, point, directional
and spot. A scene can have only one ambient light but it can have multiple
light sources of other kind. Right now, support for different light sources
is wired for WebGPU renderer only.
Initial step towards material modeling of surface. Right three reflection
parameters are set:
    diffuse_strength
        Strength of the diffuse (Lambertian) lighting component, in [0, 1].
        Defaults to 0.8.
    specular_strength
        Strength of the specular (Phong) highlight, in [0, ∞].
        Defaults to 0.9.
    specular_exponent
        Phong shininess exponent — higher values produce a tighter, sharper
        specular highlight; lower values produce a broad, soft one.
        Defaults to 16.0.
We can implement MeshPhongMaterial (from three.js) like class in future if
needed.

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@behackl

behackl commented Aug 27, 2026

Copy link
Copy Markdown
Member

Hi! This is very cool; thanks for your effort! I can look through the API and various decisions made here a bit closer later (I am particularly interested in how your approach compares to the recent 3b1b/manim migration to wgpu rendering) -- however, it is unfortunately a bit too early for introducing a new renderer.

As you might have noticed, we just introduced #4916 as a first concrete step towards improving and disentangling the render flow; the next step is already up in form of #4966 (opinions are welcome!), and I've got more refactors like that coming over the next days.

Once the render flow is cleaned up (including the introduction of a proper RendererProtocol) and the timeline is owned by the new Manager, then I'm excited to get this in. In the current state of the render flow, this would make the refactor more complicated though, and I can't have that, sorry. (I'm confident that the implementation then will actually be easier than what you had to do here, and I'll happily work with you to get this merged once we are there!)

@Alex-PLACET

Copy link
Copy Markdown

Can you made the import of the specific opengl backend dependencies lazy ?
In my case I would like to make a emscripten-forge recipe of manim and so being able to run manim in JupyterLite. In this context, opengl is not available and so it will be blocking if it's not lazily imported.
@behackl I see that you have a series of notebooks for manim, it could be easily usable into JupyterLite or https://notebook.link once it's merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants